import java.util.Stack;

/**
 * 
 * @author Guillaume PANNETIER
 * @author Bertrand LE MAROUILLE
 * @author Quentin DORVEAUX
 * @author Corentin GUICHAOUA
 * 
 * Cette classe s'occupe seulement d'afficher les noms des fonctions appelees avec leurs arguments pour permettre au developpeur de s'assurer que l'execution se deroule correctement.
 *
 */
public class YVM {
	public boolean correct; //Indique si le code analys� est correct.
	protected Stack <Integer> pileFaire;
	protected int tantQueMax = 0;

	protected Stack <Integer> pileSi;
	protected int siMax = 0;

	/**
	 * Constructeur de la classe. Il initialise les piles.
	 */
	public YVM(){
		correct = true;
		pileFaire = new Stack <Integer> ();

		pileSi = new Stack <Integer> ();
	}
	
	/**
	 * Cree l'etiquette avec le nom donne en parametre
	 * @param s Nom de l'etiquette a creer.
	 */
	public void etiq(String s){
		print(s+":");
	}
	
	/**
	 * S'il n'y a pas d'erreur, affiche "ouvrePrince"
	 */
	public void ouvrePrinc(){
		if(correct){
			print("ouvrePrinc");
		}
	}

	/**
	 * S'il n'y a pas d'erreur, affiche une etiquette de condition "SI".
	 */
	public void debutCondition(){
		if(correct){
			etiq("SI"+siMax);
			pileSi.push(siMax);
			siMax++;
		}
	}

	/**
	 * S'il n'y a pas d'erreur, affiche une etiquette "SINON"
	 */
	public void alors(){
		if(correct){
			Yaka.expression.depileType();
			iffaux("SINON"+pileSi.peek());
		}
	}

	/**
	 * S'il n'y a pas d'erreur, appelle la methode "goto" en lui indiquant l'etiquette "FSI" de la derniere condition.
	 * Cette fonction cree aussi une etiquette "SINON".
	 */
	public void sinon(){
		if(correct){
			goTo("FSI"+pileSi.peek());
			//printTab("jmp FSI"+pileSi.peek());
			etiq("SINON"+pileSi.peek());
		}
	}

	/**
	 * S'il n'y a pas d'erreur, cree une etiquette "FSI".
	 */
	public void fsiSinon(){
		if(correct)
			etiq("FSI"+pileSi.pop());
	}

	/**
	 * S'il n'y a pas d'erreur, affiche une etiquette "SINON" directement suivie d'une etiquette "FSI"
	 */
	public void fsi(){
		if(correct){
			etiq("SINON"+pileSi.peek());
			etiq("FSI"+pileSi.pop());
		}
	}

	/**
	 * S'il n'y a pas d'erreur, affiche une etiquette "FAIRE"
	 */
	public void debutIteration(){
		if(correct){
			etiq("\nFAIRE"+tantQueMax);
			pileFaire.push(tantQueMax);
			tantQueMax++;
		}
	}

	/**
	 * S'il n'y a pas d'erreur, lance la methode goto sur la derniere etiquette "FAIRE" puis affiche une etiquette "FAIT"
	 */
	public void finIteration(){
		if(correct){
			goTo("FAIRE"+pileFaire.peek());
			etiq("FAIT"+pileFaire.pop());
		}
	}

	/**
	 * Gère la condition de sortie d'une boucle FAIRE.
	 */
	public void faire(){
		if(correct){
			Yaka.expression.depileType();
			iffaux("FAIT"+pileFaire.peek());
		}
	}


	/**
	 * S'il n'y a pas d'erreur, affiche "entete"
	 */
	public void entete(){
		if(correct){
			print("entete");
		}
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "ouvrePrinc" suivi du nombre passe en parametre
	 * @param taille Taille des variables locales
	 */
	public void ouvrePrinc(int taille){
		if(correct)
			print("ouvrePrinc "+taille);
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "iconst" suivie de la valeur passee en parametre
	 * @param valeur Valeur de la constante
	 */
	public void iconst(int valeur){
		if(correct)
			print("iconst " +valeur);
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "idiv"
	 */
	public void idiv(){
		if(correct)
			print("idiv");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "iadd"
	 */
	public void iadd(){
		if(correct)
			print("iadd");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "istore" suivi de l'offset passe en parametre
	 * @param Offset de la variable a stocker
	 */
	public void istore(int offset){
		if(correct)
			print("istore "+offset);
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "iload" suivi de l'offset passe en parametre
	 * @param offset Offset de la valeur a charger.
	 */
	public void iload(int offset){
		if(correct)
			print("iload "+offset);
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "imul"
	 */
	public void imul(){
		if(correct)
			print("imul");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "isub"
	 */
	public void isub(){
		if(correct)
			print("isub");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "ior"
	 */
	public void ior(){
		if(correct)
			print("ior");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "iand"
	 */
	public void iand(){
		if(correct)
			print("iand");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "queue"
	 */
	public void queue(){
		if(correct)
			print("queue");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "ecrireChaine" suivi de la chaine de caractere passee en parametre.
	 * @param ch Chaine de caractere a afficher.
	 */
	public void ecrireChaine(String ch){
		if(correct)
			print("ecrireChaine "+ch);
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "iffaux" suivi de la chaine de caractere passee en parametre.
	 * @param ch Chaine de caractere a afficher.
	 */
	public void iffaux(String ch){
		if(correct)
			print("iffaux "+ch);
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "goTo" suivie de la chaine de caractere passee en parametre.
	 * @param ch Chaine de caractere a afficher.
	 */
	public void goTo(String ch){
		if(correct)
			print("goTo "+ch);
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "aLaLigne".
	 */
	public void aLaLigne(){
		if(correct)
			print("aLaLigne");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "ecrireEnt".
	 */
	public void ecrireEnt(){
		if(correct)
			print("ecrireEnt");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "lireEnt"
	 */
	public void lireEnt(){
		if(correct)
			print("lireEnt ");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "call" suivie du nom de la fonction passe en parametre
	 * @param nom Nom de la fonction a appeler.
	 */
	public void call(String nom){
		if(correct)
			print("call "+nom);
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "reserveRetour"
	 */
	public void reserveRetour(){
		if(correct)
			print("reserveRetour");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "ouvBloc" suivi de l'entier passe en parametre
	 * @param ent numero du bloc
	 */
	public void ouvBloc(int ent){
		if(correct)
			print("ouvBloc "+ent);
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "fermeBloc" suivi du numero de bloc calcule par la fonction.
	 */
	public void fermeBloc(){
		int ent;
		try {
			ent = 2*((IdFun)Yaka.tabIdent.chercheIdent(YakaTokenManager.fonctionLue)).getArgs().size();
			if(correct)
				print("fermeBloc "+ent);
		} catch (TabIdentException e) {
			e.printStackTrace();
		}
	}

	/**
	 * S'il n'y a pas d'erreur, affiche "ireturn" suivi du numero de bloc calcule par la fonction.
	 */
	public void ireturn(){
		int ent;
		try {
			ent = 4+2*((IdFun)Yaka.tabIdent.chercheIdent(YakaTokenManager.fonctionLue)).getArgs().size();
			print("ireturn "+ent);
		} catch (TabIdentException e) {
			e.printStackTrace();
		}
	}






	/*
	 * ************************
	 *      COMPARAISONS
	 * ************************
	 */

	/**
	 * S'il n'y a pas d'erreur, affiche iinfegal
	 */
	public void iinfegal(){
		if(correct)
			print("iinfegal");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche isup
	 */
	public void isup(){
		if(correct)
			print("isup");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche iinf
	 */
	public void iinf(){
		if(correct)
			print("iinf");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche isupegal
	 */
	public void isupegal(){
		if(correct)
			print("isupegal");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche iegal
	 */
	public void iegal(){
		if(correct)
			print("iegal");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche idiff
	 */
	public void idiff(){
		if(correct)
			print("idiff");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche ineg
	 */
	public void ineg(){
		if(correct)
			print("ineg");
	}

	/**
	 * S'il n'y a pas d'erreur, affiche inot
	 */
	public void inot(){
		if(correct)
			print("inot");
	}


	/*
	 * *******************
	 *     AFFICHAGE
	 * *******************
	 */


	public void print(String message){
		System.out.println(message);
	}

	public void printTab(String message){
		System.out.println("\t"+message);
	}
}
